package com.ayq.activiti.manager.domain.workflow.service.impl;

import com.ayq.activiti.common.util.ConstantPool;
import com.ayq.activiti.common.util.DateUtil;
import com.ayq.activiti.manager.config.ActivitiIdGenerator;
import com.ayq.activiti.manager.domain.activitimanager.entity.ActivitiManager;
import com.ayq.activiti.manager.domain.activitimanager.repository.ActivitiManagerMapper;
import com.ayq.activiti.manager.domain.applymanager.entity.ActivitiApplyManager;
import com.ayq.activiti.manager.domain.applymanager.repository.ActivitiApplyManagerMapper;
import com.ayq.activiti.manager.domain.examinedistribution.entity.ActivitiExamineDistribution;
import com.ayq.activiti.manager.domain.examinedistribution.repository.ActivitiExamineDistributionMapper;
import com.ayq.activiti.manager.domain.workflow.service.WorkFlowService;
import com.ayq.activiti.manager.dto.*;
import com.ayq.activiti.manager.entity.ActivitiApplyManagerEntity;
import com.ayq.activiti.manager.entity.ApprovalecordEntity;
import com.ayq.activiti.manager.entity.FlowInfoEntity;
import com.ayq.activiti.manager.entity.NodeInfoEntity;
import com.ayq.activiti.manager.enums.NodeInfoEnum;
import com.ayq.activiti.manager.publish.ActivitiNodeInfoUpdatePublish;
import com.ayq.activiti.manager.publish.ActivitiTaskOpinionListPublish;
import com.ayq.activiti.manager.util.RedisKit;
import com.ayq.activiti.manager.vo.ActivitiNodeInfoVO;
import com.ayq.activiti.manager.vo.ApprovalecordVO;
import com.ayq.activiti.manager.vo.WorkFlowApplyListVO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import org.activiti.bpmn.model.*;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricDetail;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricVariableUpdate;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Attachment;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * <p>工作流</p>
 *
 * @Author ayq
 * @Date 2021/3/31 14:56
 */
@Service
public class WorkFlowServiceImpl implements WorkFlowService {

    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private ActivitiManagerMapper activitiManagerMapper;
    @Autowired
    private ActivitiApplyManagerMapper activitiApplyManagerMapper;
    @Autowired
    private ActivitiExamineDistributionMapper activitiExamineDistributionMapper;
    @Autowired
    private ActivitiIdGenerator activitiIdGenerator;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private RedisKit<Object> redisKit;
    @Autowired
    private ActivitiNodeInfoUpdatePublish activitiNodeInfoUpdatePublish;
    @Autowired
    private ActivitiTaskOpinionListPublish activitiTaskOpinionListPublish;

    /**
     * <p>启动流程</p>
     * <p>方法名:startWorkFlow</p>
     *
     * @Author ayq
     * @Date 2021/3/31 15:05
     * @Param [startWorkFlowDTO]
     * @Return void
     */
    @Override
    @Transactional
    public void startWorkFlow(StartWorkFlowDTO startWorkFlowDTO) throws RuntimeException {
        if (StringUtils.isBlank(startWorkFlowDTO.getBusinessKey())) {
            throw new RuntimeException(ConstantPool.CN_ONE);
        }
        if (StringUtils.isBlank(startWorkFlowDTO.getUserId())) {
            throw new RuntimeException(ConstantPool.CN_SEVEN);
        }
        String[] split = startWorkFlowDTO.getBusinessKey().split("\\.");
        if (split.length != 4) {
            throw new RuntimeException(ConstantPool.CN_TWO + startWorkFlowDTO.getBusinessKey());
        }
        QueryWrapper<ActivitiManager> wrapper = new QueryWrapper<ActivitiManager>();
        wrapper.eq(ConstantPool.COMPANY_ID, split[2]).eq(ConstantPool.SYSTEM_ID, split[0]).eq(ConstantPool.BUSINESS_ID, split[1]);
        ActivitiManager activitiManager = activitiManagerMapper.selectOne(wrapper);
        if (activitiManager == null) {
            throw new RuntimeException(ConstantPool.CN_THREE + startWorkFlowDTO.getBusinessKey());
        }
        Map<String, Object> map = new HashMap<>();
        map.put(ConstantPool.ACTIVITI_MANAGER_ID, activitiManager.getId());
        ProcessInstance processInstance = runtimeService.startProcessInstanceById(String.valueOf(activitiManager.getProcdefId()), startWorkFlowDTO.getBusinessKey(), map);
        Task task = taskService.createTaskQuery().executionId(processInstance.getId()).singleResult();
        ActivitiApplyManager activitiApplyManager = ActivitiApplyManager.builder()
                .applyUsrId(Long.parseLong(startWorkFlowDTO.getUserId()))
                .businessKey(startWorkFlowDTO.getBusinessKey())
                .workFlowKey(activitiManager.getId())
                .createTime(new Date())
                .ruId(processInstance.getId())
                .id(Long.parseLong(activitiIdGenerator.getNextId()))
                .prodiId(activitiManager.getProcdefId())
                .urgency(0)
                .status(2)
                .applyUsrName(startWorkFlowDTO.getUserName())
                .build();
        activitiApplyManagerMapper.insert(activitiApplyManager);
        activitiNodeInfoUpdatePublish.sendActivitiNodeInfoUpdate(processInstance.getId());
    }

    /**
     * <p>获取用户审核列表</p>
     * <p>方法名:getUserTaskList</p>
     *
     * @Author ayq
     * @Date 2021/4/1 10:48
     * @Param [userTaskListDTO]
     * @Return org.ezca.esign.service.activiti.web.dto.WorkFlowApplyListDTO
     */
    @Override
    public List<WorkFlowApplyListVO> getUserTaskList(UserTaskListDTO userTaskListDTO) throws RuntimeException {
        if (StringUtils.isBlank(userTaskListDTO.getWorkFlowKey())) {
            throw new RuntimeException(ConstantPool.CN_ONE);
        }
        if (StringUtils.isBlank(userTaskListDTO.getUserId())) {
            throw new RuntimeException(ConstantPool.CN_SEVEN);
        }
        String[] split = userTaskListDTO.getWorkFlowKey().split("\\.");
        if (split.length != 3) {
            throw new RuntimeException(ConstantPool.CN_TWO + userTaskListDTO.getWorkFlowKey());
        }
        List<WorkFlowApplyListVO> list = new ArrayList<WorkFlowApplyListVO>();
        List<Task> tasks = taskService.createTaskQuery().taskCandidateUser(userTaskListDTO.getUserId()).processInstanceBusinessKeyLike(userTaskListDTO.getWorkFlowKey() + "%").list();
        for (Task task : tasks) {
            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
            String businessKey = processInstance.getBusinessKey();
            if (StringUtils.isNotBlank(businessKey)) {
                WorkFlowApplyListVO build = WorkFlowApplyListVO.builder()
                        .status(2)
                        .businessId(businessKey.split("\\.")[3])
                        .processInstanceId(processInstance.getProcessInstanceId())
                        .build();
                list.add(build);
            }
        }
        return list;
    }

    /**
     * <p>获取用户申请列表</p>
     * <p>方法名:getUserApplyList</p>
     *
     * @Author ayq
     * @Date 2021/4/6 13:45
     * @Param [userApplyListDTO]
     * @Return java.util.List<org.ezca.esign.interfaces.api.activiti.dto.WorkFlowApplyListDTO>
     */
    @Override
    public List<WorkFlowApplyListVO> getUserApplyList(UserApplyListDTO userApplyListDTO) throws RuntimeException {
        if (StringUtils.isBlank(userApplyListDTO.getWorkFlowKey())) {
            throw new RuntimeException(ConstantPool.CN_ONE);
        }
        if (StringUtils.isBlank(userApplyListDTO.getUserId())) {
            throw new RuntimeException(ConstantPool.CN_SEVEN);
        }
        QueryWrapper<ActivitiApplyManager> queryWrapper = new QueryWrapper<ActivitiApplyManager>();
        queryWrapper.like(ConstantPool.BUSINESS_KEY, userApplyListDTO.getWorkFlowKey() + "%")
                .eq(ConstantPool.STATUS, 2)
                .eq(ConstantPool.APPLY_USR_ID, userApplyListDTO.getUserId());
        List<ActivitiApplyManager> activitiApplyManagers = activitiApplyManagerMapper.selectList(queryWrapper);
        List<WorkFlowApplyListVO> list = new ArrayList<WorkFlowApplyListVO>();
        for (ActivitiApplyManager activitiApplyManager : activitiApplyManagers) {
            String businessKey = activitiApplyManager.getBusinessKey();
            if (StringUtils.isNotBlank(businessKey)) {
                WorkFlowApplyListVO build = WorkFlowApplyListVO.builder()
                        .processInstanceId(activitiApplyManager.getRuId())
                        .businessId(businessKey.split("\\.")[3])
                        .status(1)
                        .build();
                list.add(build);
            }
        }
        return list;
    }

    /**
     * <p>同意审批流程</p>
     * <p>方法名:agreeApprovalProcess</p>
     *
     * @Author ayq
     * @Date 2021/4/1 15:16
     * @Param [workFlowOpinionDTO]
     * @Return org.ezca.esign.service.activiti.web.dto.WorkFlowApplyListDTO
     */
    @Override
    @Transactional
    public WorkFlowApplyListVO agreeApprovalProcess(WorkFlowOpinionDTO workFlowOpinionDTO) throws RuntimeException {
        Task task = this.checkTaskInformation(workFlowOpinionDTO);
        WorkFlowApplyListVO workFlowApplyListDTO = WorkFlowApplyListVO.builder().build();
        Map<String, Object> variables = new HashMap<>();
        variables.put(ConstantPool.STATUS, 1);
        String processInstanceId = task.getProcessInstanceId();
        ProcessInstance pi1 = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        Authentication.setAuthenticatedUserId(workFlowOpinionDTO.getUserId());
        taskService.addComment(task.getId(), processInstanceId, workFlowOpinionDTO.getOpinion());
        //taskService.addComment(task.getId(),processInstanceId,workFlowOpinionDTO.getImgPath());
        taskService.createAttachment(ConstantPool.IMAGE, task.getId(), processInstanceId, ConstantPool.CN_FIVE, ConstantPool.CN_SIX, workFlowOpinionDTO.getImgPath());
        taskService.claim(task.getId(), workFlowOpinionDTO.getUserId());
        taskService.complete(task.getId(), variables);
        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        workFlowApplyListDTO.setStatus(2);
        if (pi == null) {
            ActivitiApplyManager build = ActivitiApplyManager.builder().status(3).build();
            UpdateWrapper<ActivitiApplyManager> wrapper1 = new UpdateWrapper<ActivitiApplyManager>();
            wrapper1.eq(ConstantPool.BUSINESS_KEY, workFlowOpinionDTO.getBusinessKey()).eq(ConstantPool.RU_ID, pi1.getId());
            activitiApplyManagerMapper.update(build, wrapper1);
            workFlowApplyListDTO.setStatus(3);
        }
        activitiNodeInfoUpdatePublish.sendActivitiNodeInfoUpdate(workFlowOpinionDTO.getProcessInstanceId());
        activitiTaskOpinionListPublish.sendActivitiTaskOpinionList(workFlowOpinionDTO);
        return workFlowApplyListDTO;
    }

    /**
     * <p>拒绝审批流程</p>
     * <p>方法名:refuseApprovalProcess</p>
     *
     * @Author ayq
     * @Date 2021/4/2 11:10
     * @Param [workFlowOpinionDTO]
     * @Return void
     */
    @Override
    public void refuseApprovalProcess(WorkFlowOpinionDTO workFlowOpinionDTO) throws RuntimeException {
        Task task = this.checkTaskInformation(workFlowOpinionDTO);
        Map<String, Object> variables = new HashMap<>();
        variables.put(ConstantPool.STATUS, 0);
        String processInstanceId = task.getProcessInstanceId();
        ProcessInstance pi1 = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        Authentication.setAuthenticatedUserId(workFlowOpinionDTO.getUserId());
        taskService.addComment(task.getId(), processInstanceId, workFlowOpinionDTO.getOpinion());
        taskService.claim(task.getId(), workFlowOpinionDTO.getUserId());
        taskService.complete(task.getId(), variables);
        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        if (pi == null) {
            ActivitiApplyManager build = ActivitiApplyManager.builder().status(5).build();
            UpdateWrapper<ActivitiApplyManager> wrapper1 = new UpdateWrapper<ActivitiApplyManager>();
            wrapper1.eq(ConstantPool.BUSINESS_KEY, workFlowOpinionDTO.getBusinessKey()).eq(ConstantPool.RU_ID, pi1.getId());
            activitiApplyManagerMapper.update(build, wrapper1);
        }
        activitiNodeInfoUpdatePublish.sendActivitiNodeInfoUpdate(workFlowOpinionDTO.getProcessInstanceId());
        activitiTaskOpinionListPublish.sendActivitiTaskOpinionList(workFlowOpinionDTO);
    }

    /**
     * <p>校验任务信息</p>
     * <p>方法名:checkTaskInformation</p>
     *
     * @Author ayq
     * @Date 2021/4/8 14:10
     * @Param [workFlowOpinionDTO]
     * @Return void
     */
    private Task checkTaskInformation(WorkFlowOpinionDTO workFlowOpinionDTO) throws RuntimeException {
        Task task = taskService.createTaskQuery().processInstanceId(workFlowOpinionDTO.getProcessInstanceId()).processInstanceBusinessKey(workFlowOpinionDTO.getBusinessKey()).singleResult();
        if (task == null) {
            throw new RuntimeException(ConstantPool.CN_FOUR);
        }
        if (StringUtils.isBlank(workFlowOpinionDTO.getUserId())) {
            throw new RuntimeException(ConstantPool.CN_SEVEN);
        }
        if (StringUtils.isBlank(workFlowOpinionDTO.getBusinessKey())) {
            throw new RuntimeException(ConstantPool.CN_ONE);
        }
        String[] split = workFlowOpinionDTO.getBusinessKey().split("\\.");
        if (split.length != 4) {
            throw new RuntimeException(ConstantPool.CN_TWO + workFlowOpinionDTO.getBusinessKey());
        }
        QueryWrapper<ActivitiExamineDistribution> wrapper = new QueryWrapper<ActivitiExamineDistribution>();
        wrapper.eq(ConstantPool.TASK_KEY, task.getTaskDefinitionKey()).eq(ConstantPool.COMPANY_ID, split[2]);
        ActivitiExamineDistribution activitiExamineDistribution = activitiExamineDistributionMapper.selectOne(wrapper);
        if (!activitiExamineDistribution.getExamineIds().contains(workFlowOpinionDTO.getUserId())) {
            throw new RuntimeException(ConstantPool.CN_TEN);
        }
        return task;
    }

    /**
     * <p>获取业务历史审核意见</p>
     * <p>方法名:getTaskOpinionList</p>
     *
     * @Author ayq
     * @Date 2021/4/6 15:46
     * @Param [workFlowOpinionDTO]
     * @Return org.ezca.esign.common.base.Ret<java.util.List < org.ezca.esign.interfaces.api.activiti.dto.ApprovalecordDTO>>
     */
    @Override
    public List<ApprovalecordVO> getTaskOpinionList(WorkFlowOpinionDTO workFlowOpinionDTO) throws RuntimeException {
        if (StringUtils.isBlank(workFlowOpinionDTO.getBusinessKey())) {
            throw new RuntimeException(ConstantPool.CN_ONE);
        }
        if (StringUtils.isBlank(workFlowOpinionDTO.getProcessInstanceId())) {
            throw new RuntimeException(ConstantPool.CN_EIGHT);
        }
        String[] split = workFlowOpinionDTO.getBusinessKey().split("\\.");
        if (split.length != 4) {
            throw new RuntimeException(ConstantPool.CN_TWO + workFlowOpinionDTO.getBusinessKey());
        }
        String key = ConstantPool.REDIS_ACTIVITI_HISTORY_GETTASKOPINIONLIST + workFlowOpinionDTO.getProcessInstanceId() + "." + workFlowOpinionDTO.getBusinessKey();
        if (redisKit.hasKey(key)) {
            List<ApprovalecordVO> list = (List<ApprovalecordVO>) redisKit.get(key);
            return list;
        } else {
            List<HistoricTaskInstance> listHis = historyService.createHistoricTaskInstanceQuery()
                    .processInstanceBusinessKey(workFlowOpinionDTO.getBusinessKey())
                    .processInstanceId(workFlowOpinionDTO.getProcessInstanceId()).list();
            if (listHis.size() == 0 || listHis == null) {
                throw new RuntimeException(ConstantPool.CN_FOUR);
            }
            List<ApprovalecordVO> list = new ArrayList<ApprovalecordVO>();
            for (HistoricTaskInstance historicTaskInstance : listHis) {
                StringBuffer userName = new StringBuffer();
                ApprovalecordVO build = this.getApprovalecordVO(split, userName, historicTaskInstance);
                list.add(build);

            }
            redisKit.set(key, list, DateUtil.getNextDayTime(), TimeUnit.SECONDS);
            return list;
        }
    }

    /**
     * <p>根据任务ID获取业务历史审核意见</p>
     * <p>方法名:getTaskOpinionToTaskId</p>
     *
     * @Author ayq
     * @Date 2021/4/19 11:12
     * @Param [taskId businessKey]
     * @Return org.ezca.esign.interfaces.api.activiti.vo.ApprovalecordVO
     */
    @Override
    public ApprovalecordVO getTaskOpinionToTaskId(String taskId, String businessKey) throws RuntimeException {
        if (StringUtils.isBlank(taskId)) {
            throw new RuntimeException(ConstantPool.CN_FIFTEEN);
        }
        if (StringUtils.isBlank(businessKey)) {
            throw new RuntimeException(ConstantPool.CN_ONE);
        }
        String[] split = businessKey.split("\\.");
        if (split.length != 4) {
            throw new RuntimeException(ConstantPool.CN_TWO + businessKey);
        }
        StringBuffer userName = new StringBuffer();
        HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery().taskId(taskId).singleResult();
        ApprovalecordVO build = this.getApprovalecordVO(split, userName, historicTaskInstance);
        return build;
    }

    private ApprovalecordVO getApprovalecordVO(String[] split, StringBuffer userName, HistoricTaskInstance historicTaskInstance) {
        QueryWrapper<ActivitiExamineDistribution> wrapper = new QueryWrapper<ActivitiExamineDistribution>();
        wrapper.eq(ConstantPool.COMPANY_ID, split[2]).eq(ConstantPool.SYSTEM_ID, split[0]).eq(ConstantPool.BUSINESS_ID, split[1]).eq(ConstantPool.TASK_KEY, historicTaskInstance.getTaskDefinitionKey());
        ActivitiExamineDistribution activitiExamineDistribution = activitiExamineDistributionMapper.selectOne(wrapper);
        String examineNames = activitiExamineDistribution.getExamineNames();
        String examineIds = activitiExamineDistribution.getExamineIds();
        if (StringUtils.isEmpty(examineNames) || StringUtils.isEmpty(examineIds)) {
            throw new RuntimeException(ConstantPool.CN_SIXTEEN);
        }
        String[] split1 = examineNames.split(",");
        String[] split2 = examineIds.split(",");
        if (StringUtils.isNotEmpty(historicTaskInstance.getAssignee())) {
            for (int i = 0; i < split2.length; i++) {
                if (StringUtils.equals(split2[i],historicTaskInstance.getAssignee())) {
                    userName.append(split1[i]);
                }
            }
        } else {
            for (int i = 0; i < split1.length; i++) {
                userName.append(split1[i]).append(",");
            }
            userName.delete(userName.length() - 1, userName.length());
        }
        ApprovalecordVO build = ApprovalecordVO.builder()
                .approvalUserName(userName.toString())
                .taskName(historicTaskInstance.getName())
                .startTime(historicTaskInstance.getStartTime())
                .endTime(historicTaskInstance.getEndTime())
                .duration(historicTaskInstance.getDurationInMillis())
                .build();
        if (StringUtils.isNotEmpty(historicTaskInstance.getAssignee())) {
            HistoricActivityInstance historicActivityInstance = historyService.createHistoricActivityInstanceQuery().processInstanceId(historicTaskInstance.getProcessInstanceId()).taskAssignee(historicTaskInstance.getAssignee()).singleResult();
            List<HistoricDetail> list = historyService.createHistoricDetailQuery().activityInstanceId(historicActivityInstance.getId()).variableUpdates().list();
            for (HistoricDetail historicDetail : list) {
                if (ConstantPool.STATUS.equals(((HistoricVariableUpdate) historicDetail).getVariableName())) {
                    build.setStatus((int) ((HistoricVariableUpdate) historicDetail).getValue());
                }
            }
        } else {
            build.setStatus(2);
        }
        List<Comment> taskComments = taskService.getTaskComments(historicTaskInstance.getId());
        for (Comment taskComment : taskComments) {
            build.setOpinion(taskComment.getFullMessage());
        }
        List<Attachment> taskAttachments = taskService.getTaskAttachments(historicTaskInstance.getId());
        for (Attachment taskAttachment : taskAttachments) {
            build.setImgPath(taskAttachment.getUrl());
        }
        return build;
    }

    /**
     * <p>校验是否有流程在运行中</p>
     * <p>方法名:checkActivitiEnd</p>
     *
     * @Author ayq
     * @Date 2021/4/8 17:11
     * @Param [checkActivitiEndDTO]
     * @Return org.ezca.esign.interfaces.api.activiti.dto.CheckActivitiEndDTO
     */
    @Override
    public CheckActivitiEndDTO checkActivitiEnd(CheckActivitiEndDTO checkActivitiEndDTO) throws RuntimeException {
        if (checkActivitiEndDTO.getCompanyId() == null) {
            throw new RuntimeException(ConstantPool.CN_TWELVE);
        }
        QueryWrapper<ActivitiApplyManager> wrapper = new QueryWrapper<ActivitiApplyManager>();
        wrapper.eq(ConstantPool.COMPANY_ID, checkActivitiEndDTO.getCompanyId()).eq(ConstantPool.STATUS, 2);
        if (activitiApplyManagerMapper.selectCount(wrapper) != 0) {
            checkActivitiEndDTO.setBool(true);
        } else {
            checkActivitiEndDTO.setBool(false);
        }
        return checkActivitiEndDTO;
    }

    /**
     * <p>获取活动节点信息</p>
     * <p>方法名:getNodeInfo</p>
     *
     * @Author ayq
     * @Date 2021/4/16 14:16
     * @Param [nodeInfoDTO]
     * @Return org.ezca.esign.interfaces.api.activiti.vo.ActivitiNodeInfoVO
     */
    @Override
    public ActivitiNodeInfoVO getNodeInfo(NodeInfoDTO nodeInfoDTO) throws RuntimeException {
        if (StringUtils.isEmpty(nodeInfoDTO.getProcessInstanceId())) {
            throw new RuntimeException(ConstantPool.CN_EIGHT);
        }
        String key = ConstantPool.REDIS_ACTIVITI_HISTORY_GETNODEINFO + nodeInfoDTO.getProcessInstanceId();
        if (redisKit.hasKey(key)) {
            ActivitiNodeInfoVO activitiNodeInfoVO = (ActivitiNodeInfoVO) redisKit.get(key);
            return activitiNodeInfoVO;
        } else {
            //获取历史流程实例
            QueryWrapper<ActivitiApplyManager> wrapper = new QueryWrapper<ActivitiApplyManager>();
            wrapper.eq(ConstantPool.RU_ID, nodeInfoDTO.getProcessInstanceId());
            ActivitiApplyManager activitiApplyManager = activitiApplyManagerMapper.selectOne(wrapper);
            if (activitiApplyManager == null) {
                throw new RuntimeException(ConstantPool.CN_SEVENTEEN);
            }
            //获取流程模型
            BpmnModel bpmnModel = repositoryService.getBpmnModel(activitiApplyManager.getProdiId());
            List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery().processInstanceId(nodeInfoDTO.getProcessInstanceId()).list();
            List<FlowInfoEntity> highLightedFlowInfos = new ArrayList<FlowInfoEntity>();
            List<NodeInfoEntity> highLightedNodeInfos = new ArrayList<NodeInfoEntity>();
            Map<String, GraphicInfo> locationMap = bpmnModel.getLocationMap();
            for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
                FlowNode mainProcess = (FlowNode) bpmnModel.getMainProcess().getFlowElement(historicActivityInstance.getActivityId(), true);
                List<SequenceFlow> incomingFlows = mainProcess.getIncomingFlows();
                //获取高亮线
                for (SequenceFlow incomingFlow : incomingFlows) {
                    FlowElement flowElement = bpmnModel.getFlowElement(incomingFlow.getId());
                    if (NodeInfoEnum.getResultEnum(8).getKey().equals(flowElement.getClass().getSimpleName())) {
                        List<Integer> waypoints = incomingFlow.getWaypoints();
                        FlowInfoEntity build = FlowInfoEntity.builder()
                                .startX(String.valueOf(waypoints.get(0)))
                                .startY(String.valueOf(waypoints.get(1)))
                                .endX(String.valueOf(waypoints.get(2)))
                                .endY(String.valueOf(waypoints.get(3)))
                                .build();
                        highLightedFlowInfos.add(build);
                    }
                }
                GraphicInfo graphicInfos = locationMap.get(mainProcess.getId());
                String simpleName = mainProcess.getClass().getSimpleName();
                switch (simpleName) {
                    case ConstantPool.USER_TASK: {
                        ApprovalecordVO approvalecordVO = this.getTaskOpinionToTaskId(historicActivityInstance.getTaskId(), activitiApplyManager.getBusinessKey());
                        ApprovalecordEntity approvalecordEntity = ApprovalecordEntity.builder()
                                .approvalUserName(approvalecordVO.getApprovalUserName())
                                .duration(approvalecordVO.getDuration())
                                .endTime(approvalecordVO.getEndTime())
                                .imgPath(approvalecordVO.getImgPath())
                                .opinion(approvalecordVO.getOpinion())
                                .organizationName(approvalecordVO.getOrganizationName())
                                .startTime(approvalecordVO.getStartTime())
                                .taskName(approvalecordVO.getTaskName())
                                .status(approvalecordVO.getStatus())
                                .build();
                        NodeInfoEntity build = NodeInfoEntity.builder()
                                .x(String.valueOf(graphicInfos.getX()))
                                .y(String.valueOf(graphicInfos.getY()))
                                .width(String.valueOf(graphicInfos.getWidth()))
                                .height(String.valueOf(graphicInfos.getHeight()))
                                .taskId(historicActivityInstance.getTaskId())
                                .executId(historicActivityInstance.getExecutionId())
                                .activitiId(historicActivityInstance.getActivityId())
                                .nodeType(NodeInfoEnum.getResultEnum(simpleName).getCode())
                                .approvalecordEntity(approvalecordEntity)
                                .build();
                        highLightedNodeInfos.add(build);
                    }
                    break;
                    case ConstantPool.EXCLUSIVE_GATEWAY: {
                        NodeInfoEntity build = NodeInfoEntity.builder()
                                .x(String.valueOf(graphicInfos.getX()))
                                .y(String.valueOf(graphicInfos.getY()))
                                .width(String.valueOf(graphicInfos.getWidth()))
                                .height(String.valueOf(graphicInfos.getHeight()))
                                .nodeType(NodeInfoEnum.getResultEnum(simpleName).getCode())
                                .build();
                        highLightedNodeInfos.add(build);

                    }
                    break;
                    case ConstantPool.START_EVENT: {
                        ActivitiApplyManagerEntity activitiApplyManagerEntity = ActivitiApplyManagerEntity.builder()
                                .applyUsrName(activitiApplyManager.getApplyUsrName())
                                .businessKey(activitiApplyManager.getBusinessKey())
                                .createTime(activitiApplyManager.getCreateTime())
                                .status(activitiApplyManager.getStatus())
                                .urgency(activitiApplyManager.getUrgency())
                                .variablesJson(activitiApplyManager.getVariablesJson())
                                .workFlowKey(activitiApplyManager.getWorkFlowKey())
                                .build();
                        NodeInfoEntity build = NodeInfoEntity.builder()
                                .x(String.valueOf(graphicInfos.getX()))
                                .y(String.valueOf(graphicInfos.getY()))
                                .width(String.valueOf(graphicInfos.getWidth()))
                                .height(String.valueOf(graphicInfos.getHeight()))
                                .activitiId(historicActivityInstance.getActivityId())
                                .nodeType(NodeInfoEnum.getResultEnum(simpleName).getCode())
                                .activitiApplyManagerEntity(activitiApplyManagerEntity)
                                .build();
                        highLightedNodeInfos.add(build);
                    }
                    break;
                    case ConstantPool.END_EVENT: {
                        NodeInfoEntity build = NodeInfoEntity.builder()
                                .x(String.valueOf(graphicInfos.getX()))
                                .y(String.valueOf(graphicInfos.getY()))
                                .width(String.valueOf(graphicInfos.getWidth()))
                                .height(String.valueOf(graphicInfos.getHeight()))
                                .activitiId(historicActivityInstance.getActivityId())
                                .nodeType(NodeInfoEnum.getResultEnum(simpleName).getCode())
                                .build();
                        highLightedNodeInfos.add(build);
                    }
                    break;
                    //待用
                    case ConstantPool.PARALLEL_GATEWAY:
                    case ConstantPool.SERVICE_TASK:
                    case ConstantPool.MANUAL_TASK: {
                    }
                    break;
                }
            }
            ActivitiNodeInfoVO build = ActivitiNodeInfoVO.builder()
                    .processInstanceId(nodeInfoDTO.getProcessInstanceId())
                    .businessKey(activitiApplyManager.getBusinessKey())
                    .highLightedFlowInfos(highLightedFlowInfos)
                    .highLightedNodeInfos(highLightedNodeInfos)
                    .status(activitiApplyManager.getStatus())
                    .build();
            redisKit.set(key, build, DateUtil.getNextDayTime(), TimeUnit.SECONDS);
            return build;
        }
    }

    /**
     * <p>根据实例ID查看流程图</p>
     * <p>方法名:getProcessInstanceIdBpmnImgs</p>
     *
     * @Author ayq
     * @Date 2021/4/16 15:17
     * @Param [processInstanceId, resp]
     * @Return void
     */
    @Override
    public void getProcessInstanceIdBpmnImgs(String processInstanceId, HttpServletResponse resp) throws Exception {
        ServletOutputStream outputStream = resp.getOutputStream();
        QueryWrapper<ActivitiApplyManager> wrapper = new QueryWrapper<ActivitiApplyManager>();
        wrapper.eq(ConstantPool.RU_ID, processInstanceId);
        ActivitiApplyManager activitiApplyManager = activitiApplyManagerMapper.selectOne(wrapper);
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(activitiApplyManager.getProdiId()).singleResult();
        InputStream imageStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getDiagramResourceName());
        // 输出图片内容
        outputStream = resp.getOutputStream();
        BufferedImage read = ImageIO.read(imageStream);
        ImageIO.write(read, ConstantPool.PNG, outputStream);
    }
}
